﻿using System;
using System.Configuration;
using System.Reflection;

namespace Middleware
{
    [Serializable]
    public class RemoteObject
    {
        public int ObjectID { get; set; }
        public int Port { get; set; }
        public string IP { get; set; }

        public RemoteObject()
            : this(Convert.ToBoolean(ConfigurationManager.AppSettings["usepooling"])) {
        }

        public RemoteObject(bool createObjects) {
            this.IP = ConfigurationManager.AppSettings["ip"];
            this.Port = Convert.ToInt32(ConfigurationManager.AppSettings["port"]);
            this.ObjectID = ObjectPooling.GetNewId();
            if (createObjects) {
                ObjectPooling.Add(this.ObjectID, this);
                CreateObjects(Convert.ToInt32(ConfigurationManager.AppSettings["pooling-size"]));
            }
        }

        protected RemoteObject(int objectId) {
            this.IP = ConfigurationManager.AppSettings["ip"];
            this.Port = Convert.ToInt32(ConfigurationManager.AppSettings["port"]);
            this.ObjectID = objectId == int.MinValue ? ObjectPooling.GetNewId() : objectId;
            ObjectPooling.Add(this.ObjectID, this);
        }

        private void CreateObjects(int poolingSize) {
            ConstructorInfo constructor = this.GetType().GetConstructor(
                BindingFlags.Instance | BindingFlags.Public, null, CallingConventions.HasThis, new Type[] { typeof(bool) }, null);

            for (int i = 0; i < (poolingSize - 1); i++) {
                RemoteObject remoteObject = constructor.Invoke(new object[] { false }) as RemoteObject;
                remoteObject.ObjectID = this.ObjectID;
                remoteObject.IP = this.IP;
                remoteObject.Port = this.Port;
                ObjectPooling.Add(this.ObjectID, remoteObject);
            }
        }

        public override bool Equals(object obj) {
            if (ReferenceEquals(null, obj)) return false;
            if (ReferenceEquals(this, obj)) return true;
            return obj.GetType() == typeof(RemoteObject) && Equals((RemoteObject)obj);
        }

        private bool Equals(RemoteObject other) {
            if (ReferenceEquals(null, other)) return false;
            if (ReferenceEquals(this, other)) return true;
            return other.ObjectID == ObjectID && other.Port == Port && Equals(other.IP, IP);
        }

        public override int GetHashCode() {
            unchecked {
                int result = ObjectID;
                result = (result * 397) ^ Port;
                result = (result * 397) ^ (IP != null ? IP.GetHashCode() : 0);
                return result;
            }
        }
    }
}